﻿using System;
using System.Collections.Generic;

namespace Allegro.Mathlib
{
    /// <summary>
    /// Uniform probability distribution
    /// </summary>
    public class UniformDistribution : IProbabilityDistribution
    {
        private double _min;
        private double _max;
        private double _coreDensity;
        /// <summary>
        /// Uniform distribution
        /// </summary>
        /// <param name="min">Min value</param>
        /// <param name="max">Max value</param>
        public UniformDistribution(double min, double max)
        {
            _min = Math.Min(min, max);
            _max = Math.Max(min, max);
            _coreDensity = 1.0 / (_max - _min);
        }
        /// <summary>
        /// Min value
        /// </summary>
        public double Min
        {
            get { return _min; }
        }
        /// <summary>
        /// Max value
        /// </summary>
        public double Max
        {
            get { return _max; }
        }
        /// <summary>
        /// Probability density
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public double Density(double x)
        {
            double density = 0;
            if (x >= _min && x <= _max)
            {
                density = _coreDensity;
            }
            return density;
        }
        /// <summary>
        /// Aggregated probability
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public double Probability(double x)
        {
            double probability;
            if (x >= _min && x <= _max)
            {
                probability = (x - _min) / (_max - _min);
            }
            else if (x > _max)
            {
                probability = 1.0;
            }
            else
            {
                probability = 0.0;
            }
            return probability;
        }
        /// <summary>
        /// Inverse
        /// </summary>
        /// <param name="p">Probability</param>
        /// <returns>Density</returns>
        public double Inverse(double p)
        {
            double x;
            if (p > 0.0 && p < 1.0)
            {
                x = _min + p * (_max - _min);
            }
            else if (p == 1.0)
            {
                x = _max;
            }
            else if (p == 0.0)
            {
                x = _min;
            }
            else
            {
                throw new ArgumentException("Probability argument must not be greater than 1 or less than 0");
            }
            return x;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public double FromStandardValue(double x)
        {
            return x * (_max - _min) + _min;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public double ToStandardValue(double x)
        {
            return (x - _min) / (_max - _min);
        }
    }
}
